package ms.unicorn.reasoning.subcribers;

import java.util.ArrayList;
import java.util.Collection;

import ms.unicorn.Element;
import ms.unicorn.Relation;
import ms.unicorn.NotificationService.Subscriber;
import ms.unicorn.NotificationService.Subscription;
import ms.unicorn.diagram.part.UnicornDiagramEditorUtil;
import ms.unicorn.reasoning.UnicornDSL;
import ms.unicorn.util.NotificationService;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gmf.runtime.notation.Bounds;
import org.eclipse.gmf.runtime.notation.LayoutConstraint;
import org.eclipse.gmf.runtime.notation.Shape;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.xtext.util.Arrays;

public class GenericEditPartSubscriber implements
		Subscriber<Notification, Object> {

public static Collection<Integer> PREFER_CHANNELS = new ArrayList<Integer>(2);

	public static String[] coordinateFeatures = new String[] {"x", "y", "width", "height"};

	static {
		PREFER_CHANNELS.add(NotificationService.CHANNEL_EDITPART);
	}
	
	@Override
	public Collection<Integer> getPreferChannels() {
		return PREFER_CHANNELS;
	}

	@Override
	public int hanldeSubscription(Object sender, int channel,
			Subscription<Notification, Object> subscription) {
		if (sender instanceof EditPart && subscription.getData() instanceof Notification) {
			Notification notification = (Notification) subscription.getData();
			View viewObj = (View)((EditPart)sender).getModel();
			Element domainObj = viewObj != null ? (Element)viewObj.getElement() : null;
			if (domainObj != null) {
				Object featureObj = notification.getFeature();
				if (featureObj instanceof EAttribute) {
					EAttribute feature = (EAttribute) featureObj;
					if (UnicornDSL.REQUIREMENT.equals(domainObj.getElementType()) && Arrays.contains(coordinateFeatures, feature.getName())) {
						int dx = 0, dy = 0;
						if (feature.getName().equals("x"))
							dx = notification.getNewIntValue() - notification.getOldIntValue();
						else
							dy = notification.getNewIntValue() - notification.getOldIntValue();
						updateDecomposeNodes(domainObj, (EditPart) sender, dx, dy);
					}
				}
			}
		}
		return NotificationService.SUBSCRIPTION_NORMAL;
	}
	
	protected void updateDecomposeNodes(Element domainObj, EditPart editPart, int dx, int dy) {
		for (Relation rel: domainObj.getOutgoing()) 
			if (UnicornDSL.REFINES.equals(rel.getElementType())) {
				GraphicalEditPart target = UnicornDiagramEditorUtil.findEditPart((GraphicalEditPart) editPart, rel.getTarget());
				if (target != null) {
					View view = (View)target.getModel();
					if (view instanceof Shape) {
						LayoutConstraint layout = ((Shape) view).getLayoutConstraint();
						if (layout instanceof Bounds) {
							Bounds bound = (Bounds) layout;
							if (dx != 0) bound.setX(bound.getX() + dx);
							if (dy != 0) bound.setY(bound.getY() + dy);
						}
					}
				}
			}
	}

}
